package com.atguigu.daijia.order.service.impl;

import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.model.entity.order.*;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.order.OrderInfoForm;
import com.atguigu.daijia.model.form.order.StartDriveForm;
import com.atguigu.daijia.model.form.order.UpdateOrderBillForm;
import com.atguigu.daijia.model.form.order.UpdateOrderCartForm;
import com.atguigu.daijia.model.vo.base.PageVo;
import com.atguigu.daijia.model.vo.order.*;
import com.atguigu.daijia.order.mapper.OrderBillMapper;
import com.atguigu.daijia.order.mapper.OrderInfoMapper;
import com.atguigu.daijia.order.mapper.OrderProfitsharingMapper;
import com.atguigu.daijia.order.mapper.OrderStatusLogMapper;
import com.atguigu.daijia.order.service.OrderInfoService;
import com.atguigu.daijia.order.service.OrderMonitorService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderStatusLogMapper orderStatusLogMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private OrderMonitorService orderMonitorService;

    @Autowired
    private OrderBillMapper orderBillMapper;

    @Autowired
    private OrderProfitsharingMapper orderProfitsharingMapper;

    /*
     * 保存订单信息
     * 返回订单id
     * */
    @Override
    public Long saveOrderInfo(OrderInfoForm orderInfoForm) {
        //向orderInfo中添加订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoForm,orderInfo);
        //订单号
        String OrderNo = UUID.randomUUID().toString().replaceAll("-","");
        orderInfo.setOrderNo(OrderNo);
        //订单状态
        orderInfo.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());//等待接单状态
        //向orderInfo中添加订单
        orderInfoMapper.insert(orderInfo);

        //生成订单之后发送延迟消息
        this.sendDelayMessage(orderInfo.getId());

        //记录订单日志
        this.log(orderInfo.getId(),orderInfo.getStatus());
        //向redis添加标识，标识该订单需要接单
        redisTemplate.opsForValue().set(RedisConstant.ORDER_ACCEPT_MARK + OrderNo,"0"
                ,RedisConstant.ORDER_ACCEPT_MARK_EXPIRES_TIME, TimeUnit.MINUTES);//15分钟过期时间
        return  orderInfo.getId();
    }

    //生成订单之后发送延迟消息
    private void sendDelayMessage(Long orderId) {
        try {
            //创建队列
            RBlockingQueue<Object> blockingQueue = redissonClient.getBlockingQueue("queue_cancel");

            //把创建的队列放入延迟队列
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);

            //发送消息到延迟队列
            //设置过期时间
            delayedQueue.offer(orderId.toString(),15,TimeUnit.MINUTES);//15分钟过期

        }catch (Exception e){
            e.printStackTrace();
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
    }

    /*
     * 根据订单id获取订单信息
     * */
    @Override
    public Integer getOrderStatus(Long orderId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,orderId).
                select(OrderInfo::getStatus);
        Integer status = orderInfoMapper.selectOne(wrapper).getStatus();
        //订单不存在
        if(status == null){
            return OrderStatus.NULL_ORDER.getStatus();
        }
        return status;
    }

    /*
     * 司机抢单 使用redisson分布式锁
     * */
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        //判断订单是否存在。。通过redis减少数据库压力
        if(!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId)){
            throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);//没有这个标识：该订单已经被抢走
        }
        //抢单
        //创建redisson锁
        RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);

        try {
            //获取锁
            boolean flag = lock.tryLock(
                    RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME//等待时间
                    , RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME//过期时间
                    , TimeUnit.SECONDS);//单位
            if(flag){
                //如果得到锁
                //判断订单是否存在。。防止重复抢单
                if(!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId)){
                    throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);//没有这个标识：该订单已经被抢走
                }
                //修改order——info订单状态为2（已经接单）
                LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(OrderInfo::getId,orderId);
                OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
                //设置订单的接单司机
                orderInfo.setDriverId(driverId);
                //设置接单时间
                orderInfo.setAcceptTime(new Date());
                //设置订单状态为已接单
                orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
                //调用方法修改
                int rows = orderInfoMapper.updateById(orderInfo);
                if(rows != 1){
                    //抢单失败
                    throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //删除redis中的抢单标识，防止别人再抢
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderId);
            }
        }catch (Exception e){
            throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }finally {
            if(lock.isLocked()){
                //如果有这个锁，释放
                lock.unlock();
            }
        }
        return true;
    }

    /*
     * 乘客端查找当前订单
     * */
    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        //封装需要的条件
        LambdaQueryWrapper<OrderInfo> wapper = new LambdaQueryWrapper<>();
        wapper.eq(OrderInfo::getCustomerId,customerId);//乘客id
        //订单各种状态的值
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
                OrderStatus.UNPAID.getStatus()
        };
        wapper.in(OrderInfo::getStatus,statusArray);
        //获取最新订单
        wapper.orderByDesc(OrderInfo::getId);//降序排列
        wapper.last("limit 1");//拿到第一条记录
        OrderInfo orderInfo = orderInfoMapper.selectOne(wapper);
        //封装到currentOrderInfoVo
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if(orderInfo != null){
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        }else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    /*
     * 司机端查找当前订单
     * */
    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        //封装需要的条件
        LambdaQueryWrapper<OrderInfo> wapper = new LambdaQueryWrapper<>();
        wapper.eq(OrderInfo::getDriverId,driverId);//司机id
        //订单各种状态的值
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
        };
        wapper.in(OrderInfo::getStatus,statusArray);
        //获取最新订单
        wapper.orderByDesc(OrderInfo::getId);//降序排列
        wapper.last("limit 1");//拿到第一条记录
        OrderInfo orderInfo = orderInfoMapper.selectOne(wapper);
        //封装到currentOrderInfoVo
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if(orderInfo != null){
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        }else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;

    }

    /*
     * 司机到达起始点
     * */
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        //更新订单状态 更新到达时间
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,orderId)
                .eq(OrderInfo::getDriverId,driverId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.DRIVER_ARRIVED.getStatus());//设置司机已到达状态
        orderInfo.setArriveTime(new Date());

        int rows = orderInfoMapper.update(orderInfo, wrapper);
        if(rows == 1){
            return true;
        }
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }

    /*
     * 更新代驾车辆信息
     * */
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,updateOrderCartForm.getOrderId())
                        .eq(OrderInfo::getDriverId,updateOrderCartForm.getDriverId());

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, orderInfo);
        orderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        int rows = orderInfoMapper.update(orderInfo, wrapper);
        if(rows == 1){
            return true;
        }
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }

    /*
     * 开启代驾
     * */
    @Override
    public Boolean startDriver(StartDriveForm startDriveForm) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,startDriveForm.getOrderId())
                .eq(OrderInfo::getDriverId,startDriveForm.getDriverId());
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(startDriveForm, orderInfo);
        orderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());//修改订单状态为开始服务
        orderInfo.setStartServiceTime(new Date());//修改订单开始时间
        int rows = orderInfoMapper.update(orderInfo, wrapper);
        if(rows == 1){
            return true;
        }
        //初始化订单监控统计数据
        OrderMonitor orderMonitor = new OrderMonitor();
        orderMonitor.setOrderId(startDriveForm.getOrderId());
        orderMonitorService.updateOrderMonitor(orderMonitor);
        return true;
    }

    /*
     * 根据订单段获取订单数
     * */
    @Override
    public Long getOrderNumByTime(Long startTime, Long endTime) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(OrderInfo::getStartServiceTime,startTime);//大于开始时间
        wrapper.le(OrderInfo::getStartServiceTime,endTime);//小于终止时间
        //得到符合条件的订单总数
        Long count = orderInfoMapper.selectCount(wrapper);
        return count;
    }

    /*
     * 结束代驾服务更新订单账单
     * */
    @Override
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        //1.更新订单信息
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,updateOrderBillForm.getOrderId())
                .eq(OrderInfo::getDriverId,updateOrderBillForm.getDriverId());
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.END_SERVICE.getStatus());
        orderInfo.setRealAmount(updateOrderBillForm.getTotalAmount());//实际支付金额
        orderInfo.setFavourFee(updateOrderBillForm.getFavourFee());
        orderInfo.setRealDistance(updateOrderBillForm.getRealDistance());
        orderInfo.setEndServiceTime(new Date());

        int rows = orderInfoMapper.update(orderInfo, wrapper);
        if(rows == 1){
            //添加账单数据
            OrderBill orderBill = new OrderBill();
            BeanUtils.copyProperties(updateOrderBillForm, orderBill);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(updateOrderBillForm.getTotalAmount());
            orderBillMapper.insert(orderBill);

            //添加分账信息
            OrderProfitsharing orderProfitsharing = new OrderProfitsharing();
            BeanUtils.copyProperties(updateOrderBillForm, orderProfitsharing);
            orderProfitsharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitsharing.setRuleId(updateOrderBillForm.getProfitsharingRuleId());
            orderProfitsharing.setStatus(1);
            orderProfitsharingMapper.insert(orderProfitsharing);
            return true;
        }
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }

    /*
     * 获取乘客订单分页列表
     * */
    @Override
    public PageVo findCustomerOrderPage(Page<OrderInfo> pageParam, Long customerId) {
        IPage<OrderListVo> pageInfo = orderInfoMapper.selectCustomerOrderPage(pageParam,customerId);
        PageVo pageVo = new PageVo(pageInfo.getRecords(),pageInfo.getPages(),pageInfo.getTotal());
        return pageVo;
    }

    /*
     * 获取司机订单分页列表
     * */
    @Override
    public PageVo findDriveOrderPage(Page<OrderInfo> pageParam, Long customerId) {
        IPage<OrderListVo> pageInfo = orderInfoMapper.selectDriveOrderPage(pageParam,customerId);
        PageVo pageVo = new PageVo(pageInfo.getRecords(),pageInfo.getPages(),pageInfo.getTotal());
        return pageVo;
    }

    /*
     * 根据订单id获取实际账单信息
     * */
    @Override
    public OrderBillVo getOrderBillInfo(Long orderId) {
        LambdaQueryWrapper<OrderBill> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderBill::getOrderId,orderId);
        OrderBill orderBill = orderBillMapper.selectOne(wrapper);

        OrderBillVo orderBillVo = new OrderBillVo();
        BeanUtils.copyProperties(orderBill,orderBillVo);

        return orderBillVo;
    }

    /*
     * 根据订单id获取实际分账信息
     * */
    @Override
    public OrderProfitsharingVo getOrderProfitsharing(Long orderId) {
        LambdaQueryWrapper<OrderProfitsharing> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderProfitsharing::getOrderId,orderId);
        OrderProfitsharing orderProfitsharing = orderProfitsharingMapper.selectOne(wrapper);

        OrderProfitsharingVo orderProfitsharingVo = new OrderProfitsharingVo();
        BeanUtils.copyProperties(orderProfitsharing,orderProfitsharingVo);

        return orderProfitsharingVo;
    }

    /*
     * 发送账单信息
     * */
    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,orderId);
        wrapper.eq(OrderInfo::getDriverId,driverId);

        //更新订单状态为未支付
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.UNPAID.getStatus());

        int rows = orderInfoMapper.update(orderInfo, wrapper);
        //判断是否只更新了自己的订单
        if(rows == 1){
            this.log(orderId, OrderStatus.UNPAID.getStatus());
            return true;
        }
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }

    /*
     * 获取订单支付信息
     * */
    @Override
    public OrderPayVo getOrderPayVo(Long orderNo, Long cutomerId) {
        OrderPayVo orderPayVo = orderInfoMapper.selectOrderPayVo(orderNo,cutomerId);
        //手动封装交易内容
        if(orderPayVo != null){
            String content = orderPayVo.getStartLocation() + " 到 " + orderPayVo.getEndLocation();
            orderPayVo.setContent(content);
        }
        return orderPayVo;
    }

    /*
     * 更改订单支付状态
     * */
    @Override
    public Boolean updateOrderPayStatus(String orderNo) {
        //1.根据订单编号查询订单状态
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getId,orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        if(orderInfo == null || orderInfo.getStatus() == OrderStatus.PAID.getStatus()){
            //没有这个订单或者已经支付，不需要更新
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }

        //更新状态
        LambdaQueryWrapper<OrderInfo> updateWrapper = new LambdaQueryWrapper<>();
        updateWrapper.eq(OrderInfo::getId,orderNo);

        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.PAID.getStatus());
        int rows = orderInfoMapper.update(updateOrderInfo, updateWrapper);
        if(rows == 1){
            return true;
        }
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }

    /*
     * 获取订单的系统奖励
     * */
    @Override
    public OrderRewardVo getOrderRewardFee(String orderNo) {
        //根据订单编号查询订单表，得到订单id
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getId, orderNo)
                .select(OrderInfo::getId, OrderInfo::getDriverId));
        //根据订单标号查询系统奖励表
        OrderBill orderBill = orderBillMapper.selectOne(new LambdaQueryWrapper<OrderBill>()
                .eq(OrderBill::getOrderId, orderInfo.getId())
                .select(OrderBill::getRewardFee));

        //封装数据
        OrderRewardVo orderRewardVo = new OrderRewardVo();
        orderRewardVo.setOrderId(orderInfo.getId());
        orderRewardVo.setDriverId(orderInfo.getDriverId());
        orderRewardVo.setRewardFee(orderBill.getRewardFee());

        return orderRewardVo;
    }

    //取消订单
    @Override
    public void orderCansel(long orderId) {
        //查询该订单
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);

        //取消订单
        if(orderInfo.getStatus() == OrderStatus.WAITING_ACCEPT.getStatus()){
            orderInfo.setStatus(OrderStatus.CANCEL_ORDER.getStatus());
            int rows = orderInfoMapper.updateById(orderInfo);

            if(rows == 1){
                //取消订单成功，取消redis中的接单标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderId);
            }
        }
    }

    /*
    * 添加订单日志
    * */
    public void log(Long orderId, Integer status){
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderId);
        orderStatusLog.setOrderStatus(status);
        orderStatusLog.setOperateTime(new Date());
        //记录订单日志
        orderStatusLogMapper.insert(orderStatusLog);
    }

}
